%{
    #include "tree.h"
    #include "lex.yy.c"

    int failed = 0;
    Node *root;
%}

%union {
    struct NODE *nodeval;
}
/* 
%nonassoc AND
%nonassoc RELOP */
%left <nodeval> AND OR
%left <nodeval> RELOP

%right <nodeval> ASSIGNOP
%left <nodeval> PLUS MINUS
%left <nodeval> STAR DIV

%right <nodeval> NOT

%token <nodeval> INT FLOAT
%token <nodeval> SEMI COMMA DOT
%token <nodeval> TYPE
%token <nodeval> LP RP LB RB LC RC
%token <nodeval> STRUCT RETURN IF ELSE WHILE
%token <nodeval> ID

%type <nodeval> Program ExtdefList Extdef ExtDecList 
%type <nodeval> Specifier StructSpecifier OptTag Tag
%type <nodeval> VarDec FunDec VarList ParamDec
%type <nodeval> CompSt StmtList Stmt 
%type <nodeval> DefList Def DecList Dec 
%type <nodeval> Exp Args


%%
/* 全局变量及函数定义 */
Program : 
    ExtdefList {
        $$ = createNode(0, $1->lineno); root = $$;
        insertChild($$, $1); 
    }
    ;
ExtdefList : 
    Extdef ExtdefList {
        $$ = createNode(1, $1->lineno); 
        insertChild($$, $1); insertChild($$, $2);
    }
    | /* empty */ {
        $$ = NULL;
    }
    ;
Extdef : 
    Specifier ExtDecList SEMI { /* 声明变量列表 */ /* 结构体全局变量 */
        $$ = createNode(2, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    } 
    | Specifier SEMI { /* 声明结构体 */
        $$ = createNode(2, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    | Specifier FunDec CompSt /* 声明函数 */ {
        $$ = createNode(2, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Specifier FunDec error SEMI {
        failed = 1;
        printf("Error type B at Line %d: Incomplement defination of function\n", @2.first_line);
    }
    ;
ExtDecList : 
    VarDec { /* 最后一个全局变量 */
        $$ = createNode(3, $1->lineno);
        insertChild($$, $1);
    }
    | VarDec COMMA ExtDecList { /* 继续定义全局变量\ */
        $$ = createNode(3, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    ;

/* 变量类型 */
Specifier : 
    TYPE { /* 基本类型 */
        $$ = createNode(4, $1->lineno);
        insertChild($$, $1);
    }
    | StructSpecifier { /* 结构体 */
        $$ = createNode(4, $1->lineno);
        insertChild($$, $1);
    }
    ;
StructSpecifier : 
    STRUCT OptTag LC DefList RC /* 定义结构体 */ {
        $$ = createNode(5, $1->lineno); 
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4); insertChild($$, $5);
    }
    | STRUCT Tag /* 结构体类型 */ {
        $$ = createNode(5, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    ;
OptTag : 
    ID { /* 结构体名(定义语句中) */
        $$ = createNode(6, $1->lineno);
        insertChild($$, $1);
        // insertSymbol($1->strval);
    }
    | /* empty */ { /* 无名结构体 */
        $$ = NULL;
    }
    ;
Tag : 
    ID { /* 结构体名(声明语句中) */
        $$ = createNode(7, $1->lineno);
        insertChild($$, $1);
    }
    ;

/* 变量函数定义 */
VarDec : 
    ID { /* 变量名 */
        $$ = createNode(8, $1->lineno);
        insertChild($$, $1);
        // insertSymbol($1->strval);
    }
    | VarDec LB INT RB { /* 数组 */
        $$ = createNode(8, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4);
    }
    ;
FunDec : 
    ID LP VarList RP { /* 有参函数 */
        $$ = createNode(9, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4);
        // insertSymbol($1->strval);
    }
    | ID LP RP { /* 无参函数 */
        $$ = createNode(9, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
        // insertSymbol($1->strval);
    }
    ;
VarList : 
    ParamDec COMMA VarList { /* 参数列表 */
        $$ = createNode(10, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | ParamDec { /* 最后一个函数参数 */
        $$ = createNode(10, $1->lineno);
        insertChild($$, $1);
    }
    ;
ParamDec : 
    Specifier VarDec { /* 单个参数 */
        $$ = createNode(11, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    ;

/* 函数体 */
CompSt : 
    LC DefList StmtList RC { /* 定义函数体/语句块 */
        $$ = createNode(12, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4);
    }
    ;
StmtList : 
    Stmt StmtList { /* 定义多条语句 */
        $$ = createNode(13, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    | /* empty */ { /* 空语句 */
        $$ = NULL;
    }
    ;
Stmt : 
    Exp SEMI { /* 表达式 */ // d
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    | Exp error SEMI {
        /* insert into tree */
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1); insertChild($$, $3);
        failed = 1; yyerror("Missing ;", @2.first_line);
    }
    | error SEMI {
        /* no insert */
        failed = 1; yyerror("Unexpected character", @1.first_line);
    }
    | CompSt { /* 内部语句快 */ // d
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1);
    }
    | RETURN Exp SEMI { /* return 语句 */
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | IF LP Exp RP Stmt { /* if 语句 */ /* 加优先级 */
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4); insertChild($$, $5);
    }
    | IF LP Exp RP Stmt ELSE Stmt { /* if else 语句 */
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4); 
        insertChild($$, $5); insertChild($$, $6); insertChild($$, $7); 
    }
    | WHILE LP Exp RP Stmt { /* while 语句 */
        $$ = createNode(14, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4); 
        insertChild($$, $5);
    }
    ;

/* 局部变量 */
DefList : 
    Def DefList { /* 定义多个类型的局部变量 */
        $$ = createNode(15, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    | /* empty */ { /* 定义局部变量结束 */
        $$ = NULL;
    }
    ;
Def : 
    Specifier DecList  SEMI { /* 多个同类型变量 */
        $$ = createNode(16, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Specifier error SEMI {
        /* no symbol declaration */
        failed = 1; yyerror("Unexpected Def", @2.first_line);
    }
    | Specifier DecList error SEMI {
        /* insert into tree to get symbol info */
        $$ = createNode(16, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $4);
        failed = 1; yyerror("Missing ;", @3.first_line);
    }
    ;
DecList : 
    Dec  { /* 局部变量 */
        $$ = createNode(17, $1->lineno);
        insertChild($$, $1);
    }
    | Dec COMMA DecList { /* 多个局部变量 */
        $$ = createNode(17, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    ;
Dec : 
    VarDec { /* 局部变量 */
        $$ = createNode(18, $1->lineno);
        insertChild($$, $1);
    }
    | VarDec ASSIGNOP Exp { /* 局部变量并赋值 */ // TODO
        $$ = createNode(18, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    ;

/* 表达式 */
Exp : 
    Exp ASSIGNOP Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp AND Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp OR Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp RELOP Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp PLUS Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp MINUS Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp STAR Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp DIV Exp { // d
        $$ = createNode(19, $1->lineno);
    }
    | LP Exp RP { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | MINUS Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    | NOT Exp { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2);
    }
    | ID LP Args RP { /* 函数调用 */ // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4);
    }
    | ID LP RP { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp LB Exp RB { /* 数组 */
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $4);
    }
    | Exp LB Exp error RB { // 这里把[...]中间的字符全部忽略， $$继承$1的值, 也就是标识符
        /* also insert into the tree */
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3); insertChild($$, $5);
        failed = 1; yyerror("Missing ]", @4.first_line);
    }
    | Exp DOT ID { /* 结构体访问表达式 */
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | ID { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1);
    }
    | INT { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1);
    }
    | FLOAT { // d
        $$ = createNode(19, $1->lineno);
        insertChild($$, $1);
    }
    ;
Args : 
    Exp COMMA Args { /* 函数参数列表 */
        $$ = createNode(20, $1->lineno);
        insertChild($$, $1); insertChild($$, $2); insertChild($$, $3);
    }
    | Exp { /* 函数参数 */
        $$ = createNode(20, $1->lineno);
        insertChild($$, $1);
    }
    ;


%%
